package com.faner4cloud.yun.common.util;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
/**
 * @author ...zz
 * @version v1
 * @summary desc
 * @since 2022/5/12 4:59 PM
 */
public class DateUtils {

	private DateUtils() {
		throw new UnsupportedOperationException();
	}

	private final static ZoneId DEFAULT_ZONEID = ZoneId.of("UTC+8");

	/**
	 * 年月 DateTimeFormatter , 格式为 yyyy年MM月
	 */
	public static final DateTimeFormatter DTF_MONTH = DateTimeFormatter.ofPattern("yyyy年MM月", Locale.CHINA);

	/**
	 * 年月 DateTimeFormatter , 格式为 yyyy-MM
	 */
	public static final DateTimeFormatter DTF_MONTH2 = DateTimeFormatter.ofPattern("yyyy-MM", Locale.CHINA);

	/**
	 * 年月日 DateTimeFormatter , 格式为 yyyy年MM月dd日
	 */
	public static final DateTimeFormatter DTF_DAY = DateTimeFormatter.ofPattern("yyyy年MM月dd日", Locale.CHINA);

	/**
	 * 年月日 DateTimeFormatter , 格式为 yyyy-MM-dd
	 */
	public static final DateTimeFormatter DTF_DAY2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");

	/**
	 * 获得次月第一天， 时间为 0时0分0秒
	 * <br>
	 * <b>默认 东8区(北京时间), UTC+8</b>
	 *
	 * @return Date
	 * @author
	 */
	public static Date firstDayOfNextMonth() {
		return firstDayOfNextMonth(DEFAULT_ZONEID);
	}

	/**
	 * 获得次月第一天， 时间为 0时0分0秒
	 *
	 * @param zoneId 时区
	 * @return Date
	 * @author
	 */
	public static Date firstDayOfNextMonth(ZoneId zoneId) {
		Objects.requireNonNull(zoneId);
		return Date.from(LocalDate.now().with(TemporalAdjusters.firstDayOfNextMonth()).atStartOfDay(zoneId).toInstant());
	}

	/**
	 * 获得当月第一天， 时间为 0时0分0秒
	 * <br>
	 * <b>默认 东8区(北京时间), UTC+8</b>
	 *
	 * @return Date
	 * @author
	 */
	public static Date firstDayOfMonth() {
		return Date.from(LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay(DEFAULT_ZONEID).toInstant());
	}

	/**
	 * 获得明天， 时间为 0时0分0秒0毫秒
	 * <br>
	 * <b>默认 东8区(北京时间), UTC+8</b>
	 * <br>
	 * 主要用于数据库查询的 截止时间 "< #{endDate}"
	 *
	 * @return Date
	 * @author
	 */
	public static Date tomorrow() {
		return tomorrow(DEFAULT_ZONEID);
	}

	/**
	 * 获得明天， 时间为 0时0分0秒0毫秒
	 * <br>
	 * 主要用于数据库查询的 截止时间 "< #{endDate}"
	 *
	 * @param zoneId 时区
	 * @return Date
	 * @author
	 */
	public static Date tomorrow(ZoneId zoneId) {
		Objects.requireNonNull(zoneId);
		return Date.from(LocalDate.now().plusDays(1L).atStartOfDay(zoneId).toInstant());
	}

	/**
	 * 获得今天， 时间为 0时0分0秒
	 * <br>
	 * <b>默认 东8区(北京时间), UTC+8</b>
	 * <br>
	 * 主要用于数据库查询的 开始时间 ">= #{startDate}"
	 *
	 * @return Date
	 * @author
	 */
	public static Date today() {
		return today(DEFAULT_ZONEID);
	}

	/**
	 * 获得今天， 时间为 0时0分0秒
	 * <br>
	 * 主要用于数据库查询的 开始时间 ">= #{startDate}"
	 *
	 * @param zoneId 时区
	 * @return Date
	 * @author
	 */
	public static Date today(ZoneId zoneId) {
		Objects.requireNonNull(zoneId);
		return Date.from(LocalDate.now().atStartOfDay(zoneId).toInstant());
	}

	/**
	 * LocalDateTime 转 Date
	 *
	 * @param localDateTime
	 * @return Date
	 * @author
	 * @throws NullPointerException - if {@code localDateTime} is {@code null}
	 */
	public static Date from(LocalDateTime localDateTime) {
		Objects.requireNonNull(localDateTime);
		return Date.from(localDateTime.atZone(DEFAULT_ZONEID).toInstant());
	}

	/**
	 * LocalDate 转 Date
	 *
	 * @param localDate
	 * @return Date
	 * @author
	 * @throws NullPointerException - if {@code localDate} is {@code null}
	 */
	public static Date from(LocalDate localDate) {
		Objects.requireNonNull(localDate);
		return from(localDate.atStartOfDay());
	}

	/**
	 * 格式化修改时间
	 * <br>
	 * 最小精度为天，到“今天”为止
	 * <br>
	 * 如果 from 为“今天”之后的时间则返回“未来”
	 *
	 * @param from 开始时间
	 */
	public static String since(Date from) {
		return since(from, false);
	}

	/**
	 * Date 转 LocalDate
	 * <br>
	 * <b>默认 东8区(北京时间), UTC+8</b>
	 *
	 * @param date
	 * @return LocalDate
	 * @author
	 */
	public static LocalDate from(Date date) {
		Objects.requireNonNull(date);
		return LocalDate.from(date.toInstant().atZone(DEFAULT_ZONEID));
	}

	/**
	 * Date 转 LocalDate
	 *
	 * @param date
	 * @param zoneId 指定时区
	 * @return LocalDate
	 */
	public static LocalDate from(Date date, ZoneId zoneId) {
		Objects.requireNonNull(date);
		Objects.requireNonNull(zoneId);
		return LocalDate.from(date.toInstant().atZone(zoneId));
	}

	/**
	 * 格式化修改时间
	 *
	 * @param from 开始时间
	 * @param high 是否采用高精度， 到小时/分钟/秒级别
	 */
	public static String since(Date from, boolean high) {
		if (from == null) {
			return null;
		}
		long diff = System.currentTimeMillis() - from.getTime();
		if (diff < 0) {
			return "未来";
		}
		// 算到秒
		diff /= 1000;
		long years = (diff / (365 * 24 * 3600));
		if (years > 0) {
			return years + "年前";
		}
		long months = (diff / (30 * 24 * 3600));
		if (months > 6) {
			return "半年前";
		} else if (months > 0) {
			return months + "个月前";
		}
		long weeks = (diff / (7 * 24 * 3600));
		if (weeks > 0) {
			return weeks + "周前";
		}
		long days = (diff / (24 * 3600));
		if (days > 1) {
			return days + "天前";
		} else if (days > 0) {
			return "昨天";
		}
		if (!high) {
			return "今天";
		} else {
			long hours = (diff / 3600);
			if (hours > 0) {
				return hours + "小时前";
			}
			long minutes = (diff / 60);
			if (minutes > 0) {
				return minutes + "分钟前";
			} else {
				return diff + "秒前";
			}
		}
	}
}
